/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package vn.passbookviet.bean;

import com.ryantenney.passkit4j.Pass;
import com.ryantenney.passkit4j.PassResource;
import com.ryantenney.passkit4j.PassSerializer;
import com.ryantenney.passkit4j.model.Barcode;
import com.ryantenney.passkit4j.model.BarcodeFormat;
import com.ryantenney.passkit4j.model.Color;
import com.ryantenney.passkit4j.model.Generic;
import com.ryantenney.passkit4j.model.Location;
import com.ryantenney.passkit4j.model.NumberField;
import com.ryantenney.passkit4j.model.StoreCard;
import com.ryantenney.passkit4j.model.TextField;
import com.ryantenney.passkit4j.sign.PassSigner;
import com.ryantenney.passkit4j.sign.PassSignerImpl;
import com.ryantenney.passkit4j.sign.PassSigningException;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.Serializable;
import java.security.KeyPair;
import java.security.NoSuchProviderException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.openssl.PasswordFinder;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;
import vn.passbookviet.ultilities.JSFUtilities;

/**
 *
 * @author Bach
 */
@ManagedBean
@ApplicationScoped
public class beanGenerate implements Serializable {

    private static final String PASS_CONTENT_TYPE = "application/vnd.apple.pkpass";
    private static final String PASS_FILE_NAME = "Pass";
    //

    public beanGenerate() {
    }
    //
    //private String logo;
    private String logoText;
    private String headerField;
    private String primaryFields;
//    private String thumbnail
    private String secondaryFields;
    private String auxiliaryFields;
    //

    public String getLogoText() {
        return logoText;
    }

    public void setLogoText(String logoText) {
        this.logoText = logoText;
    }

    public String getHeaderField() {
        return headerField;
    }

    public void setHeaderField(String headerField) {
        this.headerField = headerField;
    }

    public String getPrimaryFields() {
        return primaryFields;
    }

    public void setPrimaryFields(String primaryFields) {
        this.primaryFields = primaryFields;
    }

    public String getSecondaryFields() {
        return secondaryFields;
    }

    public void setSecondaryFields(String secondaryFields) {
        this.secondaryFields = secondaryFields;
    }

    public String getAuxiliaryFields() {
        return auxiliaryFields;
    }

    public void setAuxiliaryFields(String auxiliaryFields) {
        this.auxiliaryFields = auxiliaryFields;
    }

    //
    public StreamedContent getFile() {
        try {
            byte[] data = generateCard(
                    this.logoText, this.headerField, this.primaryFields, this.secondaryFields, this.auxiliaryFields);
//            byte[] data = generatePass();
            try {
                File f = new File(JSFUtilities.getAbsoluatePath("/temp/"), "pass.pkpass");
                f.createNewFile();
                FileOutputStream fos = new FileOutputStream(f);
                fos.write(data);
                fos.close();
                System.out.println("Wrote pass to: " + f.getAbsolutePath());
            } catch (Exception ex) {
            }
            return new DefaultStreamedContent(
                    new ByteArrayInputStream(data),
                    PASS_CONTENT_TYPE,
                    PASS_FILE_NAME);
        } catch (Exception ex) {
            Logger.getLogger(beanGenerate.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }

    private static byte[] generatePass() throws FileNotFoundException, CertificateException, NoSuchProviderException, IOException, PassSigningException {

        File fResourceFolder = new File(JSFUtilities.getAbsoluatePath("/resources/"));
        System.out.println("Path: " + fResourceFolder.getAbsolutePath());
        if (!fResourceFolder.exists()) {
            System.out.println("Folder Resource not exist !");
            return null;
        }
        File fStoreCardFolder = new File(fResourceFolder, "storecard");
        File fCerFolder = new File(fResourceFolder, "certificate");


        Pass pass = new Pass()
                .teamIdentifier("team-identifier")
                .passTypeIdentifier("pass.com.bouldercoffeeco.storeCard")
                .organizationName("Boulder Coffee Co.")
                .description("Boulder Coffee Rewards Card Example")
                .serialNumber("p69f2J")
                .webServiceURL("https://example.com/passes/")
                .authenticationToken(getRandomToken())
                .locations(new Location(37.6189722, -122.3748889))
                .barcode(new Barcode(BarcodeFormat.PDF417, "12345678"))
                .logoText("Boulder Coffee Co.")
                .foregroundColor(Color.WHITE)
                .backgroundColor(new Color(118, 74, 50))
                .passInformation(
                new StoreCard()
                .primaryFields(
                new NumberField("balance", "remaining balance", 25)
                .currencyCode("USD"))
                .auxiliaryFields(
                new TextField("level", "LEVEL", "Gold"),
                new TextField("usual", "THE USUAL", "Iced Mocha"))
                .backFields(
                new TextField("terms", "TERMS AND CONDITIONS",
                "Generico offers this pass, including all information, software, products and services available from this pass or offered as part of or in conjunction with this pass (the \"pass\"), to you, the user, conditioned upon your acceptance of all of the terms, conditions, policies and notices stated here. Generico reserves the right to make changes to these Terms and Conditions immediately by posting the changed Terms and Conditions in this location.\n\nUse the pass at your own risk. This pass is provided to you \"as is,\" without warranty of any kind either express or implied. Neither Generico nor its employees, agents, third-party information providers, merchants, licensors or the like warrant that the pass or its operation will be accurate, reliable, uninterrupted or error-free. No agent or representative has the authority to create any warranty regarding the pass on behalf of Generico. Generico reserves the right to change or discontinue at any time any aspect or feature of the pass.")));
        {
            File[] arrFileRes = fStoreCardFolder.listFiles();
            PassResource[] arrRes = new PassResource[arrFileRes.length];
            for (int i = 0; i < arrFileRes.length; i++) {
                arrRes[i] = new PassResource(arrFileRes[i].getName(), arrFileRes[i]);
            }
            pass.files(arrRes);
        }

        PassSignerImpl.Builder builder = PassSignerImpl.builder();
        builder.intermediateCertificate(new FileInputStream(new File(fCerFolder, "AppleWWDRCA.cer")));

        {
            File fPrivateKeyFile = new File(fCerFolder, "exported-key");
            BufferedReader br = new BufferedReader(new FileReader(fPrivateKeyFile));
            KeyPair kp = (KeyPair) new PEMReader(br, new PasswordFinder() {
                @Override
                public char[] getPassword() {
                    return "1234".toCharArray();
                }
            }).readObject();
            builder.privateKey(kp.getPrivate());
        }
        {
            File fSigningCertificate = new File(fCerFolder, "exported-cer");
            CertificateFactory factory = CertificateFactory.getInstance("X.509");
            X509Certificate certificate = (X509Certificate) factory.generateCertificate(new FileInputStream(fSigningCertificate));
            builder.signingCertificate(certificate);
        }

        PassSigner signer = builder.build();
        System.out.println("Signing...");
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        PassSerializer.writePkPassArchive(pass, signer, bos);
        System.out.println("Done !");
        return bos.toByteArray();
    }

    private byte[] generateCard(
            String logoText, String headerFields, String primaryFields, String secondaryFields, String auxiliaryFields)
            throws FileNotFoundException, CertificateException, NoSuchProviderException, IOException, PassSigningException {
        File fResourceFolder = new File(JSFUtilities.getAbsoluatePath("/resources/"));
        System.out.println("Path: " + fResourceFolder.getAbsolutePath());
        if (!fResourceFolder.exists()) {
            System.out.println("Folder Resource not exist !");
            return null;
        }
        File fStoreCardFolder = new File(fResourceFolder, "storecard");
        File fCerFolder = new File(fResourceFolder, "certificate");

        Pass pass = new Pass()
                .teamIdentifier("team-identifier")
                .passTypeIdentifier("pass.com.bouldercoffeeco.storeCard")
                .organizationName("Boulder Coffee Co.")
                .description("Boulder Coffee Rewards Card Example")
                .serialNumber("p69f2J")
                .logoText(logoText)
                .foregroundColor(Color.WHITE)
                .backgroundColor(new Color(118, 74, 50));

        System.out.println("String primaryFields = \"" + primaryFields + "\";");
        System.out.println("String headerFields = \"" + headerFields + "\";");
        System.out.println("String auxiliaryFields = \"" + auxiliaryFields + "\";");
        System.out.println("String secondaryFields = \"" + secondaryFields + "\";");

        Generic generic = new Generic();
        generic.primaryFields(getTextField(primaryFields));
        generic.auxiliaryFields(getTextField(auxiliaryFields));
        generic.headerFields(getTextField(headerFields));
        generic.secondaryFields(getTextField(secondaryFields));
        //
        pass.passInformation(generic);

        {
            File[] arrFileRes = fStoreCardFolder.listFiles();
            PassResource[] arrRes = new PassResource[arrFileRes.length];
            for (int i = 0; i < arrFileRes.length; i++) {
                arrRes[i] = new PassResource(arrFileRes[i].getName(), arrFileRes[i]);
            }
            pass.files(arrRes);
        }

        //<editor-fold>
        PassSignerImpl.Builder builder = PassSignerImpl.builder();
        builder.intermediateCertificate(new FileInputStream(new File(fCerFolder, "AppleWWDRCA.cer")));

        {
            File fPrivateKeyFile = new File(fCerFolder, "exported-key");
            BufferedReader br = new BufferedReader(new FileReader(fPrivateKeyFile));
            KeyPair kp = (KeyPair) new PEMReader(br, new PasswordFinder() {
                @Override
                public char[] getPassword() {
                    return "1234".toCharArray();
                }
            }).readObject();
            builder.privateKey(kp.getPrivate());
        }
        {
            File fSigningCertificate = new File(fCerFolder, "exported-cer");
            CertificateFactory factory = CertificateFactory.getInstance("X.509");
            X509Certificate certificate = (X509Certificate) factory.generateCertificate(new FileInputStream(fSigningCertificate));
            builder.signingCertificate(certificate);
        }

        //</editor-fold>
        PassSigner signer = builder.build();
        System.out.println("Signing...");
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        PassSerializer.writePkPassArchive(pass, signer, bos);
        System.out.println("Done !");

        return bos.toByteArray();
    }

    public static String getRandomToken() {
        StringBuilder sb = new StringBuilder();
        Random r = new Random();
        for (int i = 0; i < 16; i++) {
            sb.append(r.nextInt(10));
        }
        return sb.toString();
    }

    private TextField[] getTextField(String input) {
        ArrayList<TextField> arrList = new ArrayList<TextField>();
        String[] arrInput = input.split("\n");
        for (String str : arrInput) {
            str = str.trim();
            int i = str.indexOf(':');
            if (i <= 0) {
                i = 0;
                arrList.add(new TextField(getRandomToken(), "", str.substring(i)));
            } else {
                String[] a = str.split(":");
                arrList.add(new TextField(getRandomToken(), a[0], a[1]));
            }
        }
        return arrList.toArray(ARR_EMPTY);
    }
    private static final TextField[] ARR_EMPTY = new TextField[0];
}
